//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//------------------------------------------------------------------------------
//
//  File:  utils.c
//
//  Generic "utility" routines for the Marvell Littleton bootloader.
//
#include <windows.h>
#include <ceddk.h>
#include <ddkreg.h>
#include <monahans.h>
#include <Littleton.h>
#include <oal_memory.h>
#include "loader.h"

BOOL L2CacheEnable=FALSE;

extern LPBYTE g_lastAddressMapped;
extern EBOOT_CONTEXT g_EBootContext;
extern StartUp(); //entry function of eboot
#define BL_HDRSIG_SIZE 7

#define ZBANK_BASE_C_VIRTUAL        0x96500000      
DWORD CacheBufferFlag;  // NOTE: this needn't be a const variable and OEMCacheRangeFlush won't be called before KernelRelocate.
const LPVOID gpvCacheFlushBaseMemoryAddress = (LPVOID)ZBANK_BASE_C_VIRTUAL;

//------------------------------------------------------------------------------
//
//  Function:  hex_atoi
//
UINT16 hex_atoi(const char * hexstr)
{
    WORD wRet = 0;
    while (*hexstr) {
        wRet <<= 4;
        switch (*hexstr) {
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            wRet += (WORD)(*hexstr - '0');
            break;

        case 'a':
        case 'b':
        case 'c':
        case 'd':
        case 'e':
        case 'f':
            wRet += (WORD)(*hexstr - 'a');
            wRet += 10;
            break;

        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F':
            wRet += (WORD)(*hexstr - 'A');
            wRet += 10;
            break;
        }
        hexstr++;
    }
    return wRet;
}   // hex_atoi

void InitTimer(void)
{
    volatile XLLP_OST_T *pOSTReg = NULL;

#ifdef MINI_EBOOT
    pOSTReg = (volatile XLLP_OST_T *) MONAHANS_BASE_REG_PA_OST;
#else
    pOSTReg = (volatile XLLP_OST_T *) OALPAtoVA(MONAHANS_BASE_REG_PA_OST, FALSE);
#endif

    EdbgOutputDebugString("Enabling OS Timer 5\r\n");
    pOSTReg->omcr5 = 0x000000C3; // C, P set, resolution 1 Hz.
    pOSTReg->oscr5 = 0;
    pOSTReg->osmr5 = 0xFFFFFFFF; // way in the future...
}

//------------------------------------------------------------------------------
//
//  Function:  SpinForever
//
//  Halts the bootloader.
//
void SpinForever(void)
{
    EdbgOutputDebugString("SpinForever...\r\n");

    while (1)
    {
        ;
    }
}


void Reboot(void)
{
    EdbgOutputDebugString("Reboot Address 0x%X\r\n", OALVAtoPA(StartUp));
	Launch(OALVAtoPA(StartUp));
}

//------------------------------------------------------------------------------
//
//  Function:  OutputDebugStringW
//
//  Output unicode string to debug serial port.
//
void OutputDebugStringW(LPCWSTR string)
{
    while (*string != L'\0') OEMWriteDebugByte((UINT8)*string++);
}


//------------------------------------------------------------------------------
//
//  Function:  OEMReadData
//
//  Reads data from the download transport.
//
BOOL OEMReadData(DWORD cbData, LPBYTE pbData)
{
    // First, check to see if this call to OEMReadData is for an image chunk. To
    // verify, we check if the last call to OEMMapMemAddr (g_lastAddressMapped)
    // matches pbData (or is offset BL_HDRSIG_SIZE bytes from pbData).
    //
    // If so, this is a call to read an image chunk. Save the buffer size and 
    // address, so that we can flash this partial chunk when OEMContinueEraseFlash
    // is called. (Flashing while downloading is called "one-pass" update).
    //
    // If not, this is a call to read a signature or some other meta data (but
    // not an image chunk) so we do nothing to g_EbootContext and preserve the
    // last values.
    //
    // Summary of one-pass update:
    //  OEMMapMemAddr -> tells BLcommon where to store the next image chunk
    //  OEMReadData -> Reads the image chunk and saves the buffer info
    //  OEMContinueEraseFlash -> Retrieves the buffer info and flashes the chunk
    //  (Repeat)

    if( (g_lastAddressMapped == pbData) || (g_lastAddressMapped + BL_HDRSIG_SIZE == pbData) ) {
        g_EBootContext.cbData = cbData;
        g_EBootContext.pbData = pbData;
    }

    // May do increment bytes read to track download progress.

    return(EbootEtherReadData(cbData, pbData));
}


//------------------------------------------------------------------------------
//
//  Function:  OEMShowProgress
//
//  Updates a download progress indicator.
//
void OEMShowProgress(DWORD dwPacketNum)
{
    EdbgOutputDebugString(".");
}


static UINT32 IsLeapYear(UINT32 Year)
{
    UINT32 Leap;

    Leap = 0;
    if ((Year % 4) == 0)
    {
        Leap = 1;
        if ((Year % 100) == 0)
        {
            Leap = (Year % 400) ? 0 : 1;
        }
    }

    return(Leap);
}


#define ORIGINYEAR  1980
#define JAN1WEEK    2       /* Tuesday */
static unsigned int monthtable[]      = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static unsigned int monthtable_leap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

static void FormatSystemTime(UINT32 CurrTime, LPSYSTEMTIME pSysTime)
{
    UINT32 ms, sec, min, hour, day, month, year, leap;
    UINT32 *mtbl;

    ms   = 0;
    sec  = CurrTime % 60;
    min  = (CurrTime / 60);
    hour = (min / 60);
    day  = (hour / 24);

    pSysTime->wMilliseconds = ms;
    pSysTime->wSecond       = sec;
    pSysTime->wMinute       = (min % 60);
    pSysTime->wHour         = (hour % 24);
    pSysTime->wDayOfWeek    = (day + JAN1WEEK) % 7;

    year = ORIGINYEAR;
    while (TRUE)
    {
        leap = IsLeapYear(year);
        if (day < 365+leap)
            break;
        day -= 365+leap;
        year++;
    }
    pSysTime->wYear = year;

    mtbl = leap ? monthtable_leap : monthtable;
    for (month=0; month<12; month++) {
        if (day < mtbl[month])
            break;
        day -= mtbl[month];
    }

    pSysTime->wDay = day+1;
    pSysTime->wMonth = month+1;

    return;

}


BOOL OEMGetRealTime(LPSYSTEMTIME pSysTime)
{
    volatile PXA_RTC_REG *pRTCRegs = NULL;
    UINT32 CurrTime = 0;

//	volatile int * pOST;
    // Get the RTC value.
    //
    //static i=0;
	//i++;
	
#ifdef MINI_EBOOT
    pRTCRegs = (volatile XLLP_RTC_T *)MONAHANS_BASE_REG_PA_RTC;
#else
    pRTCRegs = (volatile XLLP_RTC_T *)OALPAtoVA(MONAHANS_BASE_REG_PA_RTC, FALSE);
#endif
    CurrTime  = pRTCRegs->rcnr;
//	CurrTime = i/100;
//	pOST=(volatile int *)OALPAtoVA(0x40a00010,FALSE);
//	CurrTime=(*pOST)/325000;

    FormatSystemTime(CurrTime, pSysTime);

    return(TRUE);

}


DWORD OEMEthGetSecs(void)
{
    SYSTEMTIME st;

    OEMGetRealTime( &st );

    return((60UL * (60UL * (24UL * (31UL * st.wMonth + st.wDay) + st.wHour) + st.wMinute)) + st.wSecond);
}


//------------------------------------------------------------------------------
//
//  Function:  OALGetTickCount
//
//  This function is called by some KITL libraries to obtain relative time
//  since device boot. It is mostly used to implement timeout in network
//  protocol.
//

UINT32 OALGetTickCount()
{
    return OEMEthGetSecs () * 1000;
}



BOOL NKVirtualSetAttributes(
  LPVOID lpvAddress,
  DWORD cbSize,
  DWORD dwNewFlags,
  DWORD dwMask,
  LPDWORD lpdwOldFlags
)
{	return TRUE;
}
//------------------------------------------------------------------------------
//
//  Function:  OALKitlPowerOff
//
//  This function is called as part of OEMPowerOff implementation. It should
//  save all information about KITL device and put it to power off mode.
//
VOID OALKitlPowerOff()
{
}

//------------------------------------------------------------------------------
//
//  Function:  OALKitlPowerOn
//
//  This function is called as part of OEMPowerOff implementation. It should
//  restore KITL device back to working state.
//
VOID OALKitlPowerOn()
{
}

VOID ReInitKITL()
{
}

UINT32 OALIntrTranslateIrq(UINT32 irq)
{
    return irq;
}


BOOL OALIntrTranslateSysIntr(
    UINT32 sysIntr, UINT32 *pCount, const UINT32 **ppIrqs
) 
{
    return FALSE;
}

void SC_SetLastError(DWORD code)
{
}

void* KitlGetDMABuffer(DWORD size,  PHYSICAL_ADDRESS *PA)
{
    static DWORD StartAddess=IMAGE_U2DKITL_START_UA;

    DWORD ret=StartAddess;

    memset(PA,0,sizeof(PHYSICAL_ADDRESS));

	
    PA->LowPart = ret-(DWORD)IMAGE_U2DKITL_START_UA+(DWORD)IMAGE_U2DKITL_START_PA;

    StartAddess+=size;
	
    if(StartAddess&0xFF)
    {
        StartAddess&=~0xFF;
        StartAddess+=0x100;		
    }

	return (PVOID)ret;	
}

#ifdef DEBUG
DBGPARAM dpCurSettings = 
{ 
    _T("Arava"), 
    { 
        _T("Error"), _T("Warning"), _T("Init"), _T(""), 
        _T(""), _T(""), _T(""), _T(""), 
        _T(""), _T(""), _T(""), _T(""), 
        _T("Function"), _T(""), _T(""), _T("") 
    }, 
    0
};
#endif
